﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.ComponentModel;

namespace XUtility
{
    public class PropertyClass
    {
        #region 字段
        private PropertyInfo[] _propertyInfos;
        #endregion

        #region 构造方法
        public PropertyClass(Type type)
        {
            this._propertyInfos = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
        }

        public PropertyClass(PropertyInfo[] propertyInfos)
        {
            this._propertyInfos = propertyInfos;
        }
        #endregion

        #region 属性
        public PropertyInfo[] PropertyInfos
        {
            get { return _propertyInfos; }
            set { _propertyInfos = value; }
        }
        #endregion

        #region 方法
        #region 获取单个属性值
        /// <summary>
        /// 获取单个属性值
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="t">对象</param>
        /// <param name="name">属性名称</param>
        /// <returns>属性值</returns>
        public Object GetValue<T>(T t, String name)
        {
            PropertyInfo pi = null;
            Object o = t;
            // 获取Object类型属性名称
            if (name.IndexOf('.') > -1)
            {
                String attrName = String.Empty; // 子属性名称
                String[] attrs = name.Split('.');
                if (attrs.Length == 2)
                {
                    name = attrs[0];
                    attrName = attrs[1];
                }
                PropertyInfo objProperty = this._propertyInfos.Where(q => name.Equals(q.Name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault<PropertyInfo>();
                if (objProperty != null)
                {
                    Type type = objProperty.PropertyType;        // 属性类型
                    if (type.IsClass && !String.IsNullOrWhiteSpace(attrName))
                    {
                        #region 对象属性 值
                        // Object类型且数据源格式正确(带有点号)
                        PropertyInfo[] myAttrPropertyInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); // 泛型对象属性
                        o = objProperty.GetValue(t, null); // 子属性对象类型
                        pi = myAttrPropertyInfo.Where(q => attrName.Equals(q.Name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
                        #endregion
                    }
                }
                else
                    pi = this._propertyInfos.Where(q => attrName.Equals(q.Name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault<PropertyInfo>();
            }
            else
                pi = this._propertyInfos.Where(q => name.Equals(q.Name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault<PropertyInfo>();

            return (pi != null ? GetValue(o, pi) : null);
        }

        /// <summary>
        /// 获取单个属性值
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="t">对象</param>
        /// <param name="objProperty">属性名称</param>
        /// <returns>属性值</returns>
        public Object GetValue<T>(T t, PropertyInfo objProperty)
        {
            Object val = null;

            if (null != objProperty)
            {
                #region 获取属性值
                Type type = objProperty.PropertyType;        // 属性类型

                String name = objProperty.Name;              // 属性名称 

                if (t == null)
                    val = type.IsValueType ? Activator.CreateInstance(type) : null;
                else
                    val = objProperty.GetValue(t, null);  // 属性值(统一为Sting类型)

                if (Type.GetType("System.String") == type)
                {
                    #region String 类型
                    if (null == val)
                    {
                        val = String.Empty;
                    }
                    #endregion
                }
                else if (type.IsValueType)
                {
                    if (typeof(Boolean) == type)
                    {
                        #region Boolean 类型
                        if (null == val)
                        {
                            val = false;
                        }
                        else if (val is Boolean)
                        {
                            val = (Boolean)val;
                        }
                        else
                        {
                            Double d;
                            String s = val.ToString().Trim();
                            // t/f   
                            // true/false   
                            // y/n   
                            // yes/no   
                            // <>0/0   
                            if (s.StartsWith("F", StringComparison.OrdinalIgnoreCase) || s.StartsWith("N", StringComparison.OrdinalIgnoreCase))
                            {
                                val = false;
                            }
                            else if (Double.TryParse(s, out d) && d == 0)   // numeric zero   
                            {
                                val = false;
                            }
                            else
                            {
                                val = true;
                            }
                        }
                        #endregion
                    }
                    else if (type.IsEnum)
                    {
                        #region Enum 类型
                        val = Enum.Parse(type, val.ToString(), true);
                        #endregion
                    }
                    else if (type == typeof(Guid))
                    {
                        #region Guid 类型
                        // If it's already a guid, return it.   
                        if (!(val is Guid))
                        {
                            if (val is String)
                            {
                                val = new Guid(val.ToString());
                            }
                            else
                            {
                                val = new Guid((byte[])val);
                            }
                        }
                        #endregion
                    }
                    else
                    {
                        #region 其他值类型
                        if ("Nullable`1".Equals(type.Name))
                        {
                            if (val != null)
                            {
                                val = Convert.ChangeType(val, System.Nullable.GetUnderlyingType(type));
                            }
                            else
                            {
                                val = System.DBNull.Value;
                            }
                        }
                        else
                        {
                            val = Convert.ChangeType(val, type);
                        }
                        #endregion
                    }
                }

                #endregion
            }

            return val;
        }
        #endregion

        #region 获取全部属性值
        /// <summary>
        /// 获取全部属性值
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="t">对象</param>
        /// <param name="name">属性名称</param>
        /// <returns>属性值</returns>
        public IDictionary<String, Object> GetValues<T>(T t, params String[] propertys)
        {
            IDictionary<String, Object> dic = new Dictionary<String, Object>();

            #region 获取属性值

            PropertyInfo[] propertyInfos = this._propertyInfos;
            if (propertys != null)
            {
                if (propertys.Length > 0)
                {
                    propertyInfos = this._propertyInfos.Where(q => propertys.Contains(q.Name)).ToArray<PropertyInfo>();
                }
            }

            foreach (PropertyInfo pi in propertyInfos)
            {
                dic.Add(pi.Name, GetValue(t, pi));
            }

            #endregion

            return dic;
        }
        #endregion

        #region 设置单个属性值
        /// <summary>
        /// 设置单个属性值
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="t">对象</param>
        /// <param name="name">属性名称</param>
        /// <param name="val">属性值</param>
        public void SetValue<T>(T t, String name, Object val)
        {
            // 获取Object类型属性名称
            if (name.IndexOf('.') > -1)
            {
                #region 对象
                Object o = t;

                String attrName = String.Empty; // 子属性名称
                String[] attrs = name.Split('.');
                if (attrs.Length == 2)
                {
                    name = attrs[0];
                    attrName = attrs[1];
                }
                PropertyInfo objProperty = this._propertyInfos.Where(q => name.Equals(q.Name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault<PropertyInfo>();
                if (objProperty != null)
                {
                    Type type = objProperty.PropertyType;        // 属性类型
                    if (type.IsClass && !String.IsNullOrWhiteSpace(attrName))
                    {
                        #region 对象属性 值
                        // Object类型且数据源格式正确(带有点号)
                        PropertyInfo[] myAttrPropertyInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); // 泛型对象属性
                        o = objProperty.GetValue(t, null); // 子属性对象类型
                        PropertyInfo pi = myAttrPropertyInfo.Where(q => attrName.Equals(q.Name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();

                        if (pi != null)
                        {
                            if (o == null)
                                o = Activator.CreateInstance(type, null);

                            pi.SetValue(o, val, null);
                            objProperty.SetValue(t, o, null);
                        }

                        #endregion
                    }
                }
                else
                {
                    #region 值类型，字符串
                    PropertyInfo propertyInfo = this._propertyInfos.Where(q => name.Equals(q.Name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault<PropertyInfo>();
                    if (propertyInfo != null)
                        propertyInfo.SetValue(t, val, null);
                    #endregion
                }
                #endregion
            }
            else
            {
                #region 值类型，字符串
                PropertyInfo propertyInfo = this._propertyInfos.Where(q => name.Equals(q.Name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault<PropertyInfo>();
                if (propertyInfo != null)
                    propertyInfo.SetValue(t, val, null);
                #endregion
            }
        }
        /// <summary>
        /// 设置单个属性值
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="t">对象</param>
        /// <param name="propertyInfo">属性信息</param>
        /// <param name="val">属性值</param>
        public void SetValue<T>(T t, PropertyInfo propertyInfo, Object val)
        {
            Object objValue;
            Type type = propertyInfo.PropertyType;

            if (val.GetType().Equals(type) || val.GetType().IsSubclassOf(type)) // 若数据类型匹配则直接返回数值
                objValue = val;
            else
            {
                if ("Nullable`1".Equals(type.Name))
                {
                    if (val == System.DBNull.Value)
                        val = null;
                    else
                        val = Convert.ChangeType(val, System.Nullable.GetUnderlyingType(type));
                    objValue = val;
                }
                else
                {
                    if (Type.GetType("System.DateTime") == type)
                    {
                        objValue = val.ToString().ToDateTime();
                    }
                    else
                    {
                        // 若值和类型不匹配则进行数据类型转换
                        TypeConverter converter = TypeDescriptor.GetConverter(type);
                        objValue = converter.ConvertTo(val, type);
                    }
                }
            }
            propertyInfo.SetValue(t, objValue, null);
        }

        /// <summary>
        /// 按指定类型设置单个属性值
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="t">对象</param>
        /// <param name="name">属性名称</param>
        /// <param name="val">属性值</param>
        /// <param name="type">属性类型</param>
        public void SetValue<T>(T t, String name, String val, Type type)
        {
            #region 设置属性值
            PropertyInfo propertyInfo = this._propertyInfos.Where(q => name.Equals(q.Name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault<PropertyInfo>();
            if (propertyInfo != null)
                SetValue(t, propertyInfo, (Object)val, type);
            #endregion
        }
        /// <summary>
        /// 按指定类型设置单个属性值
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="t">对象</param>
        /// <param name="propertyInfo">属性信息</param>
        /// <param name="val">属性值</param>
        /// <param name="type">属性类型</param>
        public void SetValue<T>(T t, PropertyInfo propertyInfo, Object val, Type type)
        {
            // Object val = strval;
            Object objValue;
            //Type type = propertyInfo.PropertyType;
            if (val.GetType().Equals(type) || val.GetType().IsSubclassOf(type))
            {
                //  若数据类型匹配则直接返回数值
                objValue = val;
            }
            else
            {
                //如果值为空并且类型为可空时给空值
                if (val == System.DBNull.Value && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    objValue = null;
                }
                else
                {
                    //如果类型为可空(Int32?)类型时获取基类型 
                    if (type.GetGenericTypeDefinition() == typeof(Nullable<>)) type = type.GetGenericArguments()[0];

                    if (Type.GetType("System.DateTime") == type)
                    {
                        objValue = val.ToString().ToDateTime();
                    }
                    else if (Type.GetType("System.Decimal") == type)
                    {
                        objValue = val.ToString().ToDecimal();
                    }
                    else if (Type.GetType("System.Int32") == type)
                    {
                        objValue = val.ToString().ToInt32();
                    }
                    else if (Type.GetType("System.Double") == type)
                    {
                        objValue = val.ToString().ToDouble();
                    }
                    else if (Type.GetType("System.Boolean") == type)
                    {
                        objValue = val.ToString().ToBoolean();
                    }
                    else
                    {
                        // 若值和类型不匹配则进行数据类型转换
                        TypeConverter converter = TypeDescriptor.GetConverter(type);
                        objValue = converter.ConvertTo(val, type);
                    }
                }
            }
            propertyInfo.SetValue(t, objValue, null);
        }
        #endregion

        #region 设置全部属性值
        /// <summary>
        /// 设置全部属性值
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="t">对象</param>
        /// <param name="dic">属性的键值对 [注：只能给值类型和String类型赋值]</param>
        /// <returns>属性值</returns>
        public void SetValues<T>(T t, IDictionary<String, Object> dic)
        {
            #region 设置属性值
            PropertyInfo[] propertyInfos = this._propertyInfos;
            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                Object val = dic[propertyInfo.Name];
                SetValue(t, propertyInfo, val);
            }
            #endregion
        }
        #endregion
        #endregion
    }
}
